package alp.starcode.nudtportal.framework.interceptor;

import alp.starcode.common.result.Result;
import alp.starcode.nudtportal.framework.constant.ProjectConst;
import alp.starcode.nudtportal.framework.cache.UserCache;
import alp.starcode.nudtportal.framework.constant.CodeEnum;
import alp.starcode.nudtportal.framework.login.user.User;
import alp.starcode.nudtportal.framework.util.HttpClientUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * 小程序认证拦截器
 *
 * @author hyc
 * @date 2022年6月22日15:27:50
 */
@Component
@Slf4j
public class CertificationInterceptor extends HandlerInterceptorAdapter {
    @Value("${certification.verify-nudt-token}")
    String verifyToken;
    @Value("${certification.server-url-get-token}")
    String serverUrlGetToken;
    @Resource
    UserCache userCache;
    
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.reset();
        PrintWriter out = null;
        response.setCharacterEncoding("UTF-8");
        //region 获取请求头中的参数
        String id_token = request.getHeader("id_token");
        //weChat、alipay
        String login_type = request.getHeader(ProjectConst.LOGIN_TYPE_KEY);
        if (StringUtils.isEmpty(login_type)) {
            out = response.getWriter();
            Map<String, String> map = new HashMap<>();
            map.put("code", CodeEnum.LOGIN_TYPE_EXCEPTION.getCode());
            map.put("msg", CodeEnum.LOGIN_TYPE_EXCEPTION.getMsg());
            out.print(JSONObject.toJSONString(map));
            return false;
        }
        log.debug("id_token:{},请求地址：{}", id_token, request.getRequestURI());
        //endregion
        if (StringUtils.isNotBlank(id_token)) {
            //获取一遍用户校验用户是否过期
            String key = ProjectConst.USER_PREFIX + id_token;
            User user =  (User) redisTemplate.opsForValue().get(key);
            //存在用户信息直接登录
            if (user!=null){
                return true;
            }
            //如果用户失效，校验token是否过期，没有过期继续获取用户使用，region 验证token
            String url = verifyToken;
            try {
                //region 请求小程序认证服务器[验证token]
                String resultData = HttpClientUtils.getInstance().sendHttpGet(url,id_token);
                log.info("小程序认证服务返回：{}", resultData);
                Result<Map<String, Object>> map = JSON.parseObject(resultData, Result.class);
                log.info("验证结果：" + map.toString());
                //endregion
                if (CodeEnum.SUCCESS.getCode().equals(map.getCode())) {
                    userCache.getUser((String) map.getData().get("userId"),id_token,login_type);
                    return true;
                } else if (CodeEnum.EXIST_DEVICE_LOGIN.getCode().equals(map.getCode())) {
                    log.error("验证失败-当前账号已在其它设备登录");
                    out = response.getWriter();
                    Map<String, String> result = new HashMap<>();
                    result.put("code", CodeEnum.EXIST_DEVICE_LOGIN.getCode());
                    result.put("msg", CodeEnum.EXIST_DEVICE_LOGIN.getMsg());
                    out.print(JSONObject.toJSONString(result));
                    return false;
                } else if (CodeEnum.BIND_EXIST_DEVICE_LOGIN.getCode().equals(map.getCode())) {
                    log.error("验证失败-当前账号已在其它设备登录(绑定微信)");
                    out = response.getWriter();
                    Map<String, String> result = new HashMap<>();
                    result.put("code", CodeEnum.BIND_EXIST_DEVICE_LOGIN.getCode());
                    result.put("msg", CodeEnum.BIND_EXIST_DEVICE_LOGIN.getMsg());
                    out.print(JSONObject.toJSONString(result));
                    return false;
                } else {
                    log.error("验证失败-id_token已过期");
                    out = response.getWriter();
                    Map<String, String> result = new HashMap<>();
                    result.put("code", CodeEnum.TOKEN_EXPIRE_EXCEPTION.getCode());
                    result.put("msg", CodeEnum.TOKEN_EXPIRE_EXCEPTION.getMsg());
                    out.print(JSONObject.toJSONString(result));
                    return false;
                }
            } catch (HttpServerErrorException e) {
                log.error("验证失败-id_token验证失败");
                out = response.getWriter();
                Map<String, String> map = new HashMap<>();
                map.put("code", CodeEnum.USER_VERIFY_ERROR.getCode());
                map.put("msg", CodeEnum.USER_VERIFY_ERROR.getMsg());
                out.print(JSONObject.toJSONString(map));
                return false;
            }
            //endregion
        }
        log.info("验证失败-id_token不能为空");
        Map<String, String> map = new HashMap<>();
        out = response.getWriter();
        map.put("code", CodeEnum.LOGIN_EXPIRE.getCode());
        map.put("msg", CodeEnum.LOGIN_EXPIRE.getMsg());
        map.put("url", serverUrlGetToken);
        out.print(JSONObject.toJSONString(map));
        return false;
    }
}
